#include <compilation/Program.h>
#include <fstream>


extern FILE *yyin;
extern int yyparse();
extern int yydebug;

extern compilation::Program::ParseContext parseContext;


int main(int argc, char** argv)
{
  // yydebug = 1;
  compilation::Program program;
  parseContext.setProgram(program);

  if (argc < 2)
  {
    std::cerr << "usage: " << argv[0] << " <file.c>\n";
    return 1;
  }

  std::string inputFile = argv[1];
  yyin = std::fopen(inputFile.c_str(), "r");

  while (yyparse() != 0);

  if (yyin) std::fclose(yyin);
  std::cout << std::endl;

  // Save print result after parsing.
  {
    std::string filename = inputFile + ".after_parsing.out";
    std::ofstream afterParsing(filename);
    if (!afterParsing.is_open())
    {
      std::cerr << "unable to open:"
                << filename
                << std::endl;
      return 1;
    }
    program.printWithWorkList(afterParsing);
    afterParsing << std::endl;
  }

  program.setScopes();
  program.computeDominators();
  program.computeDominationFrontiers();

  // Save print result after dominator computation.
  {
    std::string filename = inputFile + ".dominators.out";
    std::ofstream dominators(filename);
    if (!dominators.is_open())
    {
      std::cerr << "unable to open:"
                << filename
                << std::endl;
      return 1;
    }
    program.printWithWorkList(dominators);
    dominators << std::endl;
  }

  program.insertPhiFunctions();

  // Save print result after phi function insertion.
  {
    std::string filename = inputFile + ".phi_inserted.out";
    std::ofstream phi(filename);
    if (!phi.is_open())
    {
      std::cerr << "unable to open:"
                << filename
                << std::endl;
      return 1;
    }
    program.printWithWorkList(phi);
    phi << std::endl;
  }

  program.renameSSA();

  // Save print result after variable renaming.
  {
    std::string filename = inputFile + ".ssa.out";
    std::ofstream phi(filename);
    if (!phi.is_open())
    {
      std::cerr << "unable to open:"
                << filename
                << std::endl;
      return 1;
    }
    program.printWithWorkList(phi);
    phi << std::endl;
  }

  return 0;
}
